const GetGoodProject = require("lib-e.coding/cli/upload_daily_v2/get_good_project");
const ECNW = require("lib-e.coding/lib").ECodingNetWrap;
const ECN = require("lib-e.coding/lib").ECodingNet;
const path = require("path");
const Toolbox = require("./toolbox_ecodingver");
const runParallel = require("run-parallel-limit");


let _getGoodProject = (function () {
  let store = {
    project_id: 0,
    project_name: "",
    root_folder_id: "",
    _t: Date.now()
  };

  /**
* @returns {Promise<{ok:Boolean,msg:String,data:{
  * project_name:String,project_id:Number,root_folder_id:String
  * }}>}
   * @param {ECN} ecn 
   */
  let nyaa_get_project__inner = function (ecn) {
    return new Promise(async resolve => {
      let from_config = await getProject1910to12(ecn);
      if (from_config.ok) {
        return resolve({
          ok: true,
          msg: "ok",
          data: {
            project_id: from_config.data.project_id,
            project_name: from_config.data.project_name,
            root_folder_id: from_config.data.root_folder_id
          }
        })
      }
      let upv2get = await GetGoodProject.getGoodProject(ecn);
      if (upv2get.ok) {
        return resolve({
          ok: true,
          msg: "ok",
          data: {
            project_id: upv2get.data.project_id,
            project_name: upv2get.data.project_name,
            root_folder_id: upv2get.data.root_folder_id
          }
        })
      }
      return resolve({
        ok: false,
        msg: `fail get project from_coonfig and v2:${from_config.msg}:::${upv2get.msg}`
      })
    })
  };



  /**
  * @returns {Promise<{ok:Boolean,msg:String,data:{
  * project_name:String,project_id:Number,root_folder_id:String
  * }}>}
   * @param {ECN} ecn 
   */
  let nyaa_get_project = function (ecn) {
    return new Promise(async resolve => {
      if (!store.project_id) {
        let init_res = await nyaa_get_project__inner(ecn);
        if (!init_res.ok) {
          return resolve({
            ok: false,
            msg: `fail to get first result of good project:${init_res.msg}`
          })
        }
        store.project_name = init_res.data.project_name;
        store.project_id = init_res.data.project_id;
        store.root_folder_id = init_res.data.root_folder_id;
        store._t = Date.now();
        return resolve({
          ok: true,
          msg: "ok",
          data: {
            project_id: init_res.data.project_id,
            project_name: init_res.data.project_name,
            root_folder_id: init_res.data.root_folder_id
          }
        })
      } else {
        if (Date.now() - store._t > 5 * 60 * 1000) {
          let o_try_refresh = await nyaa_get_project__inner(ecn);
          if (o_try_refresh.ok) {
            store.project_name = o_try_refresh.data.project_name;
            store.project_id = o_try_refresh.data.project_id;
            store.root_folder_id = o_try_refresh.data.root_folder_id;
            store._t = Date.now();
          }
        }
        return resolve({
          ok: true,
          msg: "ok",
          data: {
            project_id: store.project_id,
            project_name: store.project_name,
            root_folder_id: store.root_folder_id
          }
        })
      }
    })
  };

  return nyaa_get_project;
})();



let ecnw = new ECNW("hujimiya_", "hujimiya@yandex.by", "tsdm65");
let p_ecnwlogin = ecnw.loginToGetInstance();

/**
 * @returns {Promise<{ok:Boolean,msg:String,data:{markdown:String}}>}
 * @param {String} dir_fullpath 
 * @param {String} nyaa_title 
 * @param {Boolean} should_try_preview 暂时没用 不去实现预览功能
 */
function ecodingBackup(dir_fullpath, nyaa_title, should_try_preview) {
  return new Promise(async resolve_toplevel => {
    let o_ecn = await p_ecnwlogin;
    if (!o_ecn.ok) {
      return resolve_toplevel({
        ok: false,
        msg: `登录e.coding失败:${o_ecn.msg}`
      })
    }
    let ecn = o_ecn.data.ecoding_net;

    let o_good = await _getGoodProject(ecn)
    if (!o_good.ok) {
      return resolve_toplevel({
        ok: false,
        msg: `不能找到合适的project:${o_good.msg}`
      })
    }
    const PROJECT_NAME = o_good.data.project_name
    const PROJECT_ID = o_good.data.project_id;
    const ROOT_FOLDER_ID = o_good.data.root_folder_id;
    /**
     * @returns {Promise<{ok:Boolean,errors:String[],data:{root_folder_id:String}}>}
     * @param {String} dir_fullpath 
     */
    const uploadDir = function (dir_fullpath) {
      return new Promise(async resolve => {
        let o_createRootDir = await ecn.createNewFolderAgainstSamename(PROJECT_NAME,
          path.basename(dir_fullpath), ROOT_FOLDER_ID);
        if (!o_createRootDir.ok) {
          return resolve({
            ok: false,
            errors: [`failed to create dir for ${dir_fullpath}:${o_createRootDir.msg}`]
          })
        }
        /**@type {string[]} */
        let errors = [];
        let o_list = await Toolbox.safeListAllInDir(dir_fullpath);
        let child_dirs = o_list.filter(e => e.stats.isDirectory());
        if (child_dirs.length >= 2) {
          child_dirs = child_dirs.sort((a, b) => {
            if (a.full_path > b.full_path) return 1;
            return -1;
          })
        }
        const dirs2cloudid = {
          [dir_fullpath]: o_createRootDir.data.folder_id
        };
        for (let cd of child_dirs) {
          let parent_dir = path.dirname(cd.full_path);
          if (dirs2cloudid[parent_dir]) {
            let o_newDir = await ecn.createNewFolderAgainstSamename(PROJECT_NAME,
              path.basename(cd.full_path), dirs2cloudid[parent_dir]);
            if (o_newDir.ok) {
              dirs2cloudid[cd.full_path] = o_newDir.data.folder_id
            } else {
              errors.push(`can not create cloud folder for child dir '${path.relative(
                dir_fullpath, cd.full_path
              )}':${o_newDir.msg}`)
            }
          } else {
            errors.push(`can not find parent folder id for ${path.relative(
              dir_fullpath, cd.full_path
            )}`)
          }
        }

        let child_files = o_list.filter(e => e.stats.isFile());
        child_files = child_files.filter(e => dirs2cloudid[path.dirname(e.full_path)]);
        let ok_files_count = 0;
        let child_tasks = child_files.map(e => {
          return async cb => {
            let o_up = await ecn.uploadFileToFolderWith5Try(e.full_path,
              PROJECT_ID, dirs2cloudid[path.dirname(e.full_path)]);
            // debugger
            if (!o_up.ok) {
              errors.push(`failed to upload ${path.relative(
                dir_fullpath, e.full_path
              )}:${o_up.msg}`)
            } else {
              ok_files_count++;
            }
            cb(null);
          }
        });
        runParallel(child_tasks, 5, (err, r) => {
          if (child_files.length == 0) {
            return resolve({
              ok: false,
              errors: [`NO files should be uploaded`]
            })
          }
          if (ok_files_count == 0) {
            return resolve({
              ok: false,
              errors: errors
            })
          }
          return resolve({
            ok: true,
            errors: errors,
            data: {
              root_folder_id: o_createRootDir.data.folder_id
            }
          })
        });



      })
    };


    let o_execUploading = await uploadDir(dir_fullpath);
    if (!o_execUploading.ok) {
      return resolve_toplevel({
        ok: false,
        msg: `uploadDir()失败:${o_execUploading.errors.join("\n")}`
      })
    }
    resolve_toplevel({
      ok: true,
      msg: "ok",
      data: {
        markdown: `
        \n### http://cd-file.liblu.me/p/${PROJECT_NAME}/folder/${o_execUploading.data.root_folder_id}
        \n 有${o_execUploading.errors.length} 条error信息:
        \n `
      }
    })
  })
}


/**
 * @returns {Promise<{ok:Boolean,msg:String,data:{
 * project_name:String,project_id:Number,root_folder_id:Number
 * }}>}
 * @param {ECN} ecn 
 */
function getProject1910to12(ecn) {
  /**@type {Array<{project_name:String,project_id:Number}>} */
  let projects = [];
  projects = projects.concat([
    // { project_name: "daily_upload_201910_1259S.CLIAU", project_id: 253254 },
    { "project_name": "daily_upload_201910_21igH.CLIAU", "project_id": 266411 },
    { "project_name": "daily_upload_201910_23EqT.CLIAU", "project_id": 269386 },
    { "project_name": "daily_upload_201910_24l4I.CLIAU", "project_id": 270116 },
    { "project_name": "daily_upload_201911_25qn1.CLIAU", "project_id": 316578 },
    { "project_name": "daily_upload_201911_27bzP.CLIAU", "project_id": 319684 },
    { "project_name": "daily_upload_201911_27WOt.CLIAU", "project_id": 319685 },
    { "project_name": "daily_upload_201911_29E6J.CLIAU", "project_id": 324100 },
    { "project_name": "daily_upload_201912_5Uyo.CLIAUT", "project_id": 331985 },
    { "project_name": "daily_upload_201912_72kb.CLIAUT", "project_id": 335116 },
    { "project_name": "daily_upload_201912_13FnY.CLIAU", "project_id": 343156 },
    { "project_name": "daily_upload_201912_16Sit.CLIAU", "project_id": 346730 },
    { "project_name": "daily_upload_201912_21LzC.CLIAU", "project_id": 356210 },
    { "project_name": "daily_upload_201912_21hrT.CLIAU", "project_id": 356253 },
    { "project_name": "daily_upload_201912_234Zf.CLIAU", "project_id": 358254 },
    { "project_name": "daily_upload_201912_23O9B.CLIAU", "project_id": 358260 },
    { project_name: "daily_upload_201912_30PRP.CLIAU", project_id: 368935 },
    { project_name: 'daily_upload_201912_31GoS.CLIAU', project_id: 370256 },
    { project_name: "daily_upload_20201_1jHw.CLIAUTO", project_id: 371590 },
    { project_name: "daily_upload_20201_7FrE.CLIAUTO", project_id: 387374 },
    { project_name: "daily_upload_20201_20kIF.CLIAUT", project_id: 1361771 }
  ]);
  return new Promise(async resolve => {
    for (let project of projects) {
      let o_get = await ecn.listAllFilesInFolder(project.project_name, 0);
      if (!o_get.ok) {
        continue;
      }
      if (!o_get.data.list.length) {
        continue;
      }
      let root_dir = o_get.data.list[0];
      if (root_dir.size < 63000) {
        return resolve({
          ok: true,
          msg: "ok",
          data: {
            project_id: project.project_id,
            project_name: project.project_name,
            root_folder_id: root_dir.file_id
          }
        })
      }
    }
    return resolve({
      ok: false,
      msg: `fail to get from config_projects`
    })
  })
}




module.exports = {
  ecodingBackup
}